{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# std::any"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`std::any` 是 C++17 引入的一个类型安全的泛型容器，可以存放任意类型的单个值（类似于动态类型变量），旨在替代一些使用 `void*` 的场景，同时提供类型安全的提取机制。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "常见成员函数\n",
    "\n",
    "| 成员函数                                                     | 说明                           |\n",
    "| ------------------------------------------------------------ | ------------------------------ |\n",
    "| `any()`                                                      | 默认构造为空值。               |\n",
    "| `any(const any& other)`                                      | 拷贝构造，复制内部对象。       |\n",
    "| `any(any&& other) noexcept`                                  | 移动构造。                     |\n",
    "| `template<class ValueType, class... Args> any(std::in_place_type_t<ValueType>, Args&&... args)` | 就地构造内部对象。             |\n",
    "| `void reset() noexcept`                                      | 清空内容。                     |\n",
    "| `void swap(any& other) noexcept`                             | 与另一个 `std::any` 交换内容。 |\n",
    "| `bool has_value() const noexcept`                            | 判断是否存有值。               |\n",
    "| `const std::type_info& type() const noexcept`                | 获取动态类型信息。             |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意事项与最佳实践\n",
    "\n",
    "1. **异常处理**：使用 `std::any_cast` 获取值时，准备捕获 `std::bad_any_cast`，或者优先使用指针版本。\n",
    "2. **性能考虑**：频繁复制大型对象可能昂贵，适合存储可移动或小对象。\n",
    "3. **小对象优化**：标准未保证具体大小，但通常对小于等于 3 指针大小对象进行内联存储。\n",
    "4. **避免滥用**：如果类型集合是已知的，优先考虑 `std::variant`，可获得更好的性能与静态类型检查。\n",
    "5. **类型擦除替代方案**：对于更复杂的需求，考虑自定义类型擦除包装器或 `std::function`、`std::unique_ptr<Base>` 等方案。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "主要特性\n",
    "\n",
    "- **类型安全**：存入值时会记住其动态类型，取出时需要进行类型检查。\n",
    "- **单值容器**：一次只能存储一个对象。\n",
    "- **值语义**：拷贝和移动语义基于存储值的复制/移动构造函数。\n",
    "- **小对象优化**：对较小类型会进行内部优化，避免动态分配。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "@0x75cc8c9b0028"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#include <any>\n",
    "#include <string>\n",
    "\n",
    "std::any a;                     // 空容器\n",
    "std::any b = 10;                // 存储 int\n",
    "std::any c = std::string(\"Hi\"); // 存储 std::string\n",
    "a = 3.14;                       // 赋值 double"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "auto d = std::make_any<std::vector<int>>(10, 42); // vector<int>，长度10，值42"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "判断是否有值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "有值\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "\n",
    "if (a.has_value()) {\n",
    "    std::cout << \"有值\\n\";\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获取存储类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "存储类型为double\n"
     ]
    }
   ],
   "source": [
    "const std::type_info& ti = a.type();\n",
    "if (ti == typeid(double)) {\n",
    "    std::cout << \"存储类型为double\\n\";\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "取出值\n",
    "- 异常：当类型不匹配时抛出 `std::bad_any_cast`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.1400000"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 返回值方式（复制或移动）\n",
    "\n",
    "double x = std::any_cast<double>(a);\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.14"
     ]
    }
   ],
   "source": [
    "// 指针方式（不抛异常，失败返回空指针）\n",
    "\n",
    "if (double* px = std::any_cast<double>(&a)) {\n",
    "    std::cout << *px;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "清空"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "a.reset(); // 变为空\n",
    "if (a.has_value()) {\n",
    "    std::cout << \"有值\\n\";\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 代码示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Login: Alice\n"
     ]
    }
   ],
   "source": [
    "#include <any>\n",
    "#include <iostream>\n",
    "#include <string>\n",
    "#include <unordered_map>\n",
    "#include <vector>\n",
    "#include <functional>\n",
    "\n",
    "class EventBus {\n",
    "public:\n",
    "    template <typename Event>\n",
    "    void subscribe(std::function<void(const Event&)> handler) {\n",
    "        auto wrapper = [handler](const std::any& payload) {\n",
    "            if (const Event* event = std::any_cast<Event>(&payload)) {\n",
    "                handler(*event);\n",
    "            }\n",
    "        };\n",
    "        handlers[typeid(Event).hash_code()].push_back(std::move(wrapper));\n",
    "    }\n",
    "\n",
    "    template <typename Event>\n",
    "    void publish(const Event& event) const {\n",
    "        auto it = handlers.find(typeid(Event).hash_code());\n",
    "        if (it == handlers.end()) return;\n",
    "        std::any payload = event;\n",
    "        for (const auto& h : it->second) {\n",
    "            h(payload);\n",
    "        }\n",
    "    }\n",
    "\n",
    "private:\n",
    "    using Handler = std::function<void(const std::any&)>;\n",
    "    std::unordered_map<std::size_t, std::vector<Handler>> handlers;\n",
    "};\n",
    "\n",
    "struct LoginEvent {\n",
    "    std::string user;\n",
    "};\n",
    "\n",
    "{\n",
    "    EventBus bus;\n",
    "    bus.subscribe<LoginEvent>([](const LoginEvent& e) {\n",
    "        std::cout << \"Login: \" << e.user << '\\n';\n",
    "    });\n",
    "\n",
    "    bus.publish(LoginEvent{\"Alice\"});\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `std::variant`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`std::variant` 是 C++17 引入的联合类型（代数数据类型），可在预定义的一组类型中存储其中一种，为类型安全提供编译期保障。它是 `std::any` 的常见替代方案，当可能的类型集合在编译期已知时，应优先考虑使用 `std::variant`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "常见成员函数\n",
    "\n",
    "| 成员函数                                                     | 说明                                                       |\n",
    "| ------------------------------------------------------------ | ---------------------------------------------------------- |\n",
    "| `variant()`                                                  | 默认构造，构造第一个备选类型的默认值。                     |\n",
    "| `variant(T&&)`                                               | 从备选类型构造或赋值，参与重载决议。                       |\n",
    "| `variant(const variant& other)`                              | 拷贝构造（备选类型的拷贝构造必须有效）。                   |\n",
    "| `variant(variant&& other)`                                   | 移动构造。                                                 |\n",
    "| `template <class T, class... Args> variant(std::in_place_type_t<T>, Args&&...)` | 就地构造备选类型。                                         |\n",
    "| `template <size_t I, class... Args> variant(std::in_place_index_t<I>, Args&&...)` | 按索引就地构造。                                           |\n",
    "| `void swap(variant& other)`                                  | 交换内容。                                                 |\n",
    "| `size_t index() const noexcept`                              | 返回当前存储类型的索引，若为空则返回 `std::variant_npos`。 |\n",
    "| `bool valueless_by_exception() const noexcept`               | 返回是否因为异常而处于无值状态。                           |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最佳实践建议\n",
    "\n",
    "1. **有限类型集合首选**：当备选类型在编译期已知且有限时，优先使用 `std::variant`。\n",
    "2. **使用访问器**：推荐使用 `std::visit` 或定义合适的访问器对象处理不同类型，便于维护和扩展。\n",
    "3. **避免重复类型**：虽然允许，但会增加可读性和维护成本，除非必须通过索引区分。\n",
    "4. **处理空值状态**：在可能抛异常的操作后，检查 `valueless_by_exception()` 并恢复有效状态。\n",
    "5. **结合 `std::monostate`**：可用 `std::monostate` 作为第一个类型表示“空”值，为默认构造提供非异常的状态。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "主要特性\n",
    "\n",
    "- **受限联合**：只允许存储模板参数列表中的一种类型。\n",
    "- **编译期类型安全**：所有操作都会在编译期对类型进行检查。\n",
    "- **索引管理**：每个备选类型有对应的索引，可通过 `index()` 查询当前类型的索引。\n",
    "- **访问接口丰富**：提供 `std::get`、`std::get_if`、`std::visit` 等方法。\n",
    "- **备选类型允许重复**：可在同一个 `variant` 中存在多个相同类型，但需通过索引区分。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "定义与初始化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "@0x759758a20028"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#include <variant>\n",
    "#include <string>\n",
    "\n",
    "std::variant<int, double, std::string> v;   // 默认构造，存储第一个类型的默认值（int{} 即 0）\n",
    "\n",
    "v = 42;                      // 存储 int\n",
    "v = 3.14;                    // 存储 double\n",
    "v = std::string(\"Hello\");    // 存储 std::string"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "@0x75cc8c9b0098"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 也可以使用 `std::in_place_index` 或 `std::in_place_type` 进行原地构造\n",
    "\n",
    "std::variant<std::vector<int>, std::string> data(std::in_place_index<0>, 10, 42);\n",
    "// data 存储 std::vector<int>{10 个元素，值为 42}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "检查当前存储类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当前存储 std::string\n"
     ]
    }
   ],
   "source": [
    "if (std::holds_alternative<double>(v)) {\n",
    "    std::cout << \"当前存储 double\\n\";\n",
    "}\n",
    "\n",
    "if (std::holds_alternative<std::string>(v)) {\n",
    "    std::cout << \"当前存储 std::string\\n\";\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "访问存储值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "std::bad_variant_access caught: std::get: wrong index for variant\n"
     ]
    }
   ],
   "source": [
    "// std::get\n",
    "\n",
    "#include <iostream>\n",
    "#include <string>\n",
    "#include <variant>\n",
    "\n",
    "{\n",
    "    try {\n",
    "        double d = std::get<double>(v); // 运行期仍可能抛出 std::bad_variant_access\n",
    "        std::cout << \"double: \" << d << '\\n';\n",
    "    } catch (const std::bad_variant_access& ex) {\n",
    "        std::cerr << \"std::bad_variant_access caught: \" << ex.what() << '\\n';\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello\n"
     ]
    }
   ],
   "source": [
    "// std::get_if\n",
    "\n",
    "if (auto p = std::get_if<std::string>(&v)) {\n",
    "    // p 是指向内部 std::string 的指针，失败时返回 nullptr\n",
    "    std::cout << *p << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 访问者模式：`std::visit`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`std::visit` 接受一个可调用对象，并根据当前存储类型调用对应的重载"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello\n"
     ]
    }
   ],
   "source": [
    "std::visit([](auto&& value) {\n",
    "    std::cout << value << '\\n';\n",
    "}, v);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "string: Hello\n"
     ]
    }
   ],
   "source": [
    "struct Printer {\n",
    "    void operator()(int i) const { std::cout << \"int: \" << i << '\\n'; }\n",
    "    void operator()(double d) const { std::cout << \"double: \" << d << '\\n'; }\n",
    "    void operator()(const std::string& s) const { std::cout << \"string: \" << s << '\\n'; }\n",
    "};\n",
    "\n",
    "std::visit(Printer{}, v);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可结合 `std::overloaded`（C++20）或自定义结构体实现多种类型处理："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `valueless_by_exception`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在某些异常情况下（例如赋值期间抛出异常），`std::variant` 可能进入“无值”状态。此时：\n",
    "\n",
    "- `index() == std::variant_npos`\n",
    "- 访问其值会抛出 `std::bad_variant_access`\n",
    "- 可调用 `emplace`、重新赋值或移动以恢复有效状态"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 代码示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 表达式求值\n",
    "\n",
    "#include <iostream>\n",
    "#include <string>\n",
    "#include <variant>\n",
    "\n",
    "using Value = std::variant<int, double, std::string>;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13.14\n",
      "Hello World\n"
     ]
    }
   ],
   "source": [
    "Value add(const Value& lhs, const Value& rhs) {\n",
    "    return std::visit([](const auto& a, const auto& b) -> Value {\n",
    "        using A = std::decay_t<decltype(a)>;\n",
    "        using B = std::decay_t<decltype(b)>;\n",
    "\n",
    "        if constexpr (std::is_same_v<A, std::string> && std::is_same_v<B, std::string>) {\n",
    "            return a + b;\n",
    "        } else if constexpr ((std::is_same_v<A, int> || std::is_same_v<A, double>) &&\n",
    "                             (std::is_same_v<B, int> || std::is_same_v<B, double>)) {\n",
    "            return static_cast<double>(a) + static_cast<double>(b);\n",
    "        } else {\n",
    "            throw std::runtime_error(\"Unsupported operands\");\n",
    "        }\n",
    "    }, lhs, rhs);\n",
    "}\n",
    "\n",
    "{\n",
    "    Value v1 = 10;\n",
    "    Value v2 = 3.14;\n",
    "    Value v3 = std::string(\"Hello \");\n",
    "    Value v4 = std::string(\"World\");\n",
    "\n",
    "    std::cout << std::get<double>(add(v1, v2)) << '\\n';\n",
    "    std::cout << std::get<std::string>(add(v3, v4)) << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `std::variant` VS `std::any `"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 特性     | `std::any`                     | `std::variant`            |\n",
    "| -------- | ------------------------------ | ------------------------- |\n",
    "| 类型集合 | 任意类型                       | 编译期确定的一组类型      |\n",
    "| 类型检查 | 运行时                         | 编译时（静态）            |\n",
    "| 内存开销 | 高：需要动态类型信息           | 固定：最大备选类型的大小  |\n",
    "| 类型获取 | `std::any_cast` + 类型判断     | `std::get` / `std::visit` |\n",
    "| 使用场景 | 类型未知或插件系统，运行时动态 | 类型有限集，编译期已知    |"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "C++17",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
